/*
 * Copyright (C) 2009 Kristopher T Babic
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of
 * the GNU General Public License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program;
 * if not, see <http://www.gnu.org/licenses>.
 */

package edu.idp.client;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Point2D;
import java.util.Vector;

//  JPanel
/**
 *
 * @author Kristopher T Babic
 */
public class BDirection extends java.awt.Component implements MouseListener, java.awt.event.MouseMotionListener {

    private Point2D.Double curLoc = null;
    private Point2D.Double center = null;
    private Point2D.Double unitVector = null;

    private java.awt.Image buffer = null;
    private boolean initialized = false;

    private Vector changeListeners;

    private java.awt.Point leftArrow = null;
    private java.awt.Point rightArrow = null;

    public BDirection() {
        setBackground(new Color(12632256));
//    System.out.println("Panel has been created.");
        java.awt.Rectangle bounds = getBounds();
        //curLoc = new java.awt.Point(bounds.width, bounds.height/2);
        //center = new java.awt.Point(bounds.width/2, bounds.height/2);
        this.addMouseListener((MouseListener) this);
        this.addMouseMotionListener(this);
    }

    private void setUnitVector(Point2D.Double uv) {
        this.unitVector = uv;
    }

    public Point2D.Double getUnitVector() {
        return this.unitVector;
    }

    public void paint(java.awt.Graphics compGraphics) {

        java.awt.Rectangle bounds = getBounds();
        if (buffer == null)
            buffer = this.createImage(bounds.width, bounds.height);

        Graphics g = buffer.getGraphics();

        if (!initialized) {
            g.setColor(getBackground());
            g.fillRect(0, 0, bounds.width, bounds.height);
            g.setColor(Color.black);
            //g.fillOval();
            g.fillArc(0, 0, bounds.width, bounds.height, 0, 360);
            //g.drawArc(1, 1, bounds.width-2, bounds.height-2, 0, 360);
            initialized = true;
        }
        g.setColor(new Color(200, 200, 200));
        g.fillArc(2, 2, bounds.width - 4, bounds.height - 4, 0, 360);

        if (curLoc == null) {
            curLoc = new Point2D.Double();
            calculateNewLocation(new java.awt.Point(bounds.width, bounds.height / 2));
        }

        if (center == null)
            center = new Point2D.Double(((double) bounds.width) / 2.0, ((double) bounds.height) / 2.0);

        g.setColor(Color.black);
        g.drawLine((int) center.x, (int) center.y, (int) curLoc.x, (int) curLoc.y);
        g.drawLine((int) curLoc.x, (int) curLoc.y, leftArrow.x, leftArrow.y);
        g.drawLine((int) curLoc.x, (int) curLoc.y, rightArrow.x, rightArrow.y);

        compGraphics.drawImage(buffer, 0, 0, this);
    }

    private void calculateNewLocation(java.awt.Point mouseLoc) {
        java.awt.Rectangle bounds = this.getBounds();

        Point2D.Double loc = new Point2D.Double((double) mouseLoc.x, (double) mouseLoc.y);
        if (center == null)
            center = new Point2D.Double(((double) bounds.width) / 2.0, ((double) bounds.height) / 2.0);
        Point2D.Double newLoc = new Point2D.Double(loc.x - center.x, loc.y - center.y);

        double l = Math.sqrt(Math.pow((double) newLoc.x, 2.0) + Math.pow((double) newLoc.y, 2.0));

        double x = (double) newLoc.x / l;
        double y = (double) newLoc.y / l;

        this.setUnitVector(new Point2D.Double(x, y));

        double mult = Math.sqrt(Math.pow((double) (bounds.width / 2.0) - 2.0, 2.0) / (Math.pow(x, 2.0) + Math.pow(y, 2.0)));

        if (mult < 0.0)
            mult = mult * -1.0;

        Point2D.Double finalLoc = new Point2D.Double((x * mult), (y * mult));
        curLoc.x = finalLoc.x + center.x;
        curLoc.y = finalLoc.y + center.y;

        fireChangeEvent(new ChangeEvent(this));
        mult = Math.sqrt(Math.pow(.85 * ((double) (bounds.width / 2.0) - 2.0), 2.0) / (Math.pow(x, 2.0) + Math.pow(y, 2.0)));

        if (mult < 0.0)
            mult = mult * -1.0;

        leftArrow = new java.awt.Point((int) (mult * (x * Math.cos(Math.toRadians(-10)) - y * Math.sin(Math.toRadians(-10))) + center.x), (int) (mult * (x * Math.sin(Math.toRadians(-10)) + y * Math.cos(Math.toRadians(-10))) + center.y));
        rightArrow = new java.awt.Point((int) (mult * (x * Math.cos(Math.toRadians(10)) - y * Math.sin(Math.toRadians(10))) + center.x), (int) (mult * (x * Math.sin(Math.toRadians(10)) + y * Math.cos(Math.toRadians(10))) + center.y));
    }

    public void processMouseEvent(MouseEvent e) {
        int id = e.getID();
        if (!this.contains(e.getPoint()))
            return;

        if (id == MouseEvent.MOUSE_CLICKED ||
                id == MouseEvent.MOUSE_PRESSED ||
                id == MouseEvent.MOUSE_DRAGGED) {
            //curLoc = e.getPoint();

            calculateNewLocation(e.getPoint());
            repaint();
        }
    }

    public void mouseDragged(MouseEvent e) {
        if (!this.contains(e.getPoint()))
            return;
        //curLoc = e.getPoint();
        calculateNewLocation(e.getPoint());
        repaint();
    }

    public void mouseMoved(MouseEvent e) {
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
    }

    /**
     * *****************************************
     * methods for adding and manipulating ChangeEvents
     * ******************************************
     */
    public synchronized void addChangeListener(ChangeListener cl) {
        if (changeListeners == null)
            changeListeners = new Vector();
        changeListeners.addElement(cl);
    }

    public synchronized void removeChangeListener(ChangeListener cl) {
        if (changeListeners != null && cl != null)
            changeListeners.removeElement(cl);
    }

    protected void fireChangeEvent(ChangeEvent ce) {
        if (changeListeners == null)
            return;
        Vector targets;
        synchronized (this) {
            targets = (Vector) changeListeners.clone();
        }

        for (int i = 0; i < targets.size(); i++) {
            ChangeListener target = (ChangeListener) targets.elementAt(i);
            target.stateChanged(ce);
        }

    }


}


